﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Reflection;
using System.Runtime.Serialization;

using com.calitha.goldparser;
using com.calitha.goldparser.lalr;
using com.calitha.commons;

using Vestras.StarCraft2.Luna.Parser.Ast;

namespace Vestras.StarCraft2.Luna.Parser {
    [Serializable()]
    class SymbolException : Exception {
        public SymbolException(string message) : base(message) { }
        public SymbolException(string message, Exception inner) : base(message, inner) { }
        protected SymbolException(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }

    [Serializable()]
    class RuleException : Exception {
        public RuleException(string message) : base(message) { }
        public RuleException(string message, Exception inner) : base(message, inner) { }
        protected RuleException(SerializationInfo info, StreamingContext context) : base(info, context) { }
    }

    public enum SymbolConstants : int {
        SYMBOL_EOF = 0, // (EOF)
        SYMBOL_ERROR = 1, // (Error)
        SYMBOL_WHITESPACE = 2, // (Whitespace)
        SYMBOL_COMMENTLINE = 3, // (Comment Line)
        SYMBOL_MINUS = 4, // '-'
        SYMBOL_EXCLAM = 5, // '!'
        SYMBOL_EXCLAMEQ = 6, // '!='
        SYMBOL_PERCENT = 7, // '%'
        SYMBOL_AMP = 8, // '&'
        SYMBOL_AMPAMP = 9, // '&&'
        SYMBOL_AMPEQ = 10, // '&='
        SYMBOL_LPARAN = 11, // '('
        SYMBOL_RPARAN = 12, // ')'
        SYMBOL_TIMES = 13, // '*'
        SYMBOL_TIMESEQ = 14, // '*='
        SYMBOL_COMMA = 15, // ','
        SYMBOL_DOT = 16, // '.'
        SYMBOL_DIV = 17, // '/'
        SYMBOL_DIVEQ = 18, // '/='
        SYMBOL_SEMI = 19, // ';'
        SYMBOL_LBRACKET = 20, // '['
        SYMBOL_RBRACKET = 21, // ']'
        SYMBOL_CARET = 22, // '^'
        SYMBOL_CARETEQ = 23, // '^='
        SYMBOL_LBRACE = 24, // '{'
        SYMBOL_PIPE = 25, // '|'
        SYMBOL_PIPEPIPE = 26, // '||'
        SYMBOL_PIPEEQ = 27, // '|='
        SYMBOL_RBRACE = 28, // '}'
        SYMBOL_TILDE = 29, // '~'
        SYMBOL_PLUS = 30, // '+'
        SYMBOL_PLUSEQ = 31, // '+='
        SYMBOL_LT = 32, // '<'
        SYMBOL_LTLT = 33, // '<<'
        SYMBOL_LTLTEQ = 34, // '<<='
        SYMBOL_LTEQ = 35, // '<='
        SYMBOL_EQ = 36, // '='
        SYMBOL_MINUSEQ = 37, // '-='
        SYMBOL_EQEQ = 38, // '=='
        SYMBOL_GT = 39, // '>'
        SYMBOL_GTEQ = 40, // '>='
        SYMBOL_GTGT = 41, // '>>'
        SYMBOL_GTGTEQ = 42, // '>>='
        SYMBOL_ABILCMD = 43, // abilcmd
        SYMBOL_ACTOR = 44, // actor
        SYMBOL_ACTORSCOPE = 45, // actorscope
        SYMBOL_AIFILTER = 46, // aifilter
        SYMBOL_BANK = 47, // bank
        SYMBOL_BOOL = 48, // bool
        SYMBOL_BREAK = 49, // break
        SYMBOL_BYTE = 50, // byte
        SYMBOL_CAMERAINFO = 51, // camerainfo
        SYMBOL_CHAR = 52, // char
        SYMBOL_COLOR = 53, // color
        SYMBOL_CONST = 54, // const
        SYMBOL_CONTINUE = 55, // continue
        SYMBOL_DECLITERAL = 56, // DecLiteral
        SYMBOL_DOODAD = 57, // doodad
        SYMBOL_ELSE = 58, // else
        SYMBOL_FIXED = 59, // fixed
        SYMBOL_FLOATLITERAL = 60, // FloatLiteral
        SYMBOL_HEXLITERAL = 61, // HexLiteral
        SYMBOL_ID = 62, // Id
        SYMBOL_IF = 63, // if
        SYMBOL_INCLUDE = 64, // include
        SYMBOL_INT = 65, // int
        SYMBOL_MARKER = 66, // marker
        SYMBOL_NATIVE = 67, // native
        SYMBOL_OCTLITERAL = 68, // OctLiteral
        SYMBOL_ORDER = 69, // order
        SYMBOL_PLAYERGROUP = 70, // playergroup
        SYMBOL_POINT = 71, // point
        SYMBOL_REGION = 72, // region
        SYMBOL_RETURN = 73, // return
        SYMBOL_REVEALER = 74, // revealer
        SYMBOL_SOUND = 75, // sound
        SYMBOL_SOUNDLINK = 76, // soundlink
        SYMBOL_STATIC = 77, // static
        SYMBOL_STRING = 78, // string
        SYMBOL_STRINGLITERAL = 79, // StringLiteral
        SYMBOL_STRUCT = 80, // struct
        SYMBOL_TEXT = 81, // text
        SYMBOL_TIMER = 82, // timer
        SYMBOL_TRANSMISSIONSOURCE = 83, // transmissionsource
        SYMBOL_TRIGGER = 84, // trigger
        SYMBOL_TYPEDEF = 85, // typedef
        SYMBOL_UNIT = 86, // unit
        SYMBOL_UNITFILTER = 87, // unitfilter
        SYMBOL_UNITGROUP = 88, // unitgroup
        SYMBOL_UNITREF = 89, // unitref
        SYMBOL_VOID = 90, // void
        SYMBOL_WAVE = 91, // wave
        SYMBOL_WAVEINFO = 92, // waveinfo
        SYMBOL_WAVETARGET = 93, // wavetarget
        SYMBOL_WHILE = 94, // while
        SYMBOL_ARRAY = 95, // <Array>
        SYMBOL_BASE = 96, // <Base>
        SYMBOL_BASETYPES = 97, // <BaseTypes>
        SYMBOL_BLOCK = 98, // <Block>
        SYMBOL_DECL = 99, // <Decl>
        SYMBOL_DECLS = 100, // <Decls>
        SYMBOL_EXPR = 101, // <Expr>
        SYMBOL_FUNCDECL = 102, // <Func Decl>
        SYMBOL_FUNCID = 103, // <Func ID>
        SYMBOL_FUNCPROTO = 104, // <Func Proto>
        SYMBOL_IDENTIFIER = 105, // <Identifier>
        SYMBOL_INCLUDEDECL = 106, // <Include Decl>
        SYMBOL_MEMBERACCESS = 107, // <Member Access>
        SYMBOL_MOD = 108, // <Mod>
        SYMBOL_NATIVEDECL = 109, // <Native Decl>
        SYMBOL_NATIVEID = 110, // <Native ID>
        SYMBOL_NORMALSTM = 111, // <Normal Stm>
        SYMBOL_OPADD = 112, // <Op Add>
        SYMBOL_OPAND = 113, // <Op And>
        SYMBOL_OPASSIGN = 114, // <Op Assign>
        SYMBOL_OPBINAND = 115, // <Op BinAND>
        SYMBOL_OPBINOR = 116, // <Op BinOR>
        SYMBOL_OPBINXOR = 117, // <Op BinXOR>
        SYMBOL_OPCOMPARE = 118, // <Op Compare>
        SYMBOL_OPEQUATE = 119, // <Op Equate>
        SYMBOL_OPMULT = 120, // <Op Mult>
        SYMBOL_OPOR = 121, // <Op Or>
        SYMBOL_OPPOINTER = 122, // <Op Pointer>
        SYMBOL_OPSHIFT = 123, // <Op Shift>
        SYMBOL_OPUNARY = 124, // <Op Unary>
        SYMBOL_PARAM = 125, // <Param>
        SYMBOL_PARAMEXPRESSIONS = 126, // <Param Expressions>
        SYMBOL_PARAMS = 127, // <Params>
        SYMBOL_STM = 128, // <Stm>
        SYMBOL_STMLIST = 129, // <Stm List>
        SYMBOL_STRUCTDECL = 130, // <Struct Decl>
        SYMBOL_STRUCTDEF = 131, // <Struct Def>
        SYMBOL_THENSTM = 132, // <Then Stm>
        SYMBOL_TYPE = 133, // <Type>
        SYMBOL_TYPEDEFDECL = 134, // <Typedef Decl>
        SYMBOL_VALUE = 135, // <Value>
        SYMBOL_VAR = 136, // <Var>
        SYMBOL_VARDECL = 137, // <Var Decl>
        SYMBOL_VARITEM = 138, // <Var Item>
        SYMBOL_VARLIST = 139  // <Var List>
    };

    public enum RuleConstants : int {
        RULE_IDENTIFIER_ID = 0, // <Identifier> ::= Id
        RULE_DECLS = 1, // <Decls> ::= <Decl> <Decls>
        RULE_DECLS2 = 2, // <Decls> ::= 
        RULE_DECL = 3, // <Decl> ::= <Func Decl>
        RULE_DECL2 = 4, // <Decl> ::= <Func Proto>
        RULE_DECL3 = 5, // <Decl> ::= <Native Decl>
        RULE_DECL4 = 6, // <Decl> ::= <Struct Decl>
        RULE_DECL5 = 7, // <Decl> ::= <Var Decl>
        RULE_DECL6 = 8, // <Decl> ::= <Include Decl>
        RULE_DECL7 = 9, // <Decl> ::= <Typedef Decl>
        RULE_FUNCPROTO_LPARAN_RPARAN_SEMI = 10, // <Func Proto> ::= <Func ID> '(' <Params> ')' ';'
        RULE_FUNCPROTO_LPARAN_RPARAN_SEMI2 = 11, // <Func Proto> ::= <Func ID> '(' ')' ';'
        RULE_FUNCDECL_LPARAN_RPARAN = 12, // <Func Decl> ::= <Func ID> '(' <Params> ')' <Block>
        RULE_FUNCDECL_LPARAN_RPARAN2 = 13, // <Func Decl> ::= <Func ID> '(' ')' <Block>
        RULE_NATIVEDECL_NATIVE_LPARAN_RPARAN_SEMI = 14, // <Native Decl> ::= native <Native ID> '(' <Params> ')' ';'
        RULE_NATIVEDECL_NATIVE_LPARAN_RPARAN_SEMI2 = 15, // <Native Decl> ::= native <Native ID> '(' ')' ';'
        RULE_PARAMS_COMMA = 16, // <Params> ::= <Param> ',' <Params>
        RULE_PARAMS = 17, // <Params> ::= <Param>
        RULE_PARAM = 18, // <Param> ::= <Type> <Identifier>
        RULE_PARAM2 = 19, // <Param> ::= <Identifier> <Identifier>
        RULE_FUNCID = 20, // <Func ID> ::= <Mod> <Type> <Identifier>
        RULE_FUNCID2 = 21, // <Func ID> ::= <Type> <Identifier>
        RULE_FUNCID3 = 22, // <Func ID> ::= <Mod> <Identifier> <Identifier>
        RULE_FUNCID4 = 23, // <Func ID> ::= <Identifier> <Identifier>
        RULE_NATIVEID = 24, // <Native ID> ::= <Type> <Identifier>
        RULE_TYPEDEFDECL_TYPEDEF_SEMI = 25, // <Typedef Decl> ::= typedef <Type> <Array> <Identifier> ';'
        RULE_TYPEDEFDECL_TYPEDEF_SEMI2 = 26, // <Typedef Decl> ::= typedef <Identifier> <Array> <Identifier> ';'
        RULE_TYPEDEFDECL_TYPEDEF_SEMI3 = 27, // <Typedef Decl> ::= typedef <Type> <Identifier> ';'
        RULE_TYPEDEFDECL_TYPEDEF_SEMI4 = 28, // <Typedef Decl> ::= typedef <Identifier> <Identifier> ';'
        RULE_STRUCTDECL_STRUCT_LBRACE_RBRACE_SEMI = 29, // <Struct Decl> ::= struct <Identifier> '{' <Struct Def> '}' ';'
        RULE_STRUCTDEF = 30, // <Struct Def> ::= <Var Decl> <Struct Def>
        RULE_STRUCTDEF2 = 31, // <Struct Def> ::= 
        RULE_INCLUDEDECL_INCLUDE_STRINGLITERAL = 32, // <Include Decl> ::= include StringLiteral
        RULE_VARDECL_SEMI = 33, // <Var Decl> ::= <Mod> <Type> <Array> <Var> <Var List> ';'
        RULE_VARDECL_SEMI2 = 34, // <Var Decl> ::= <Type> <Array> <Var> <Var List> ';'
        RULE_VARDECL_SEMI3 = 35, // <Var Decl> ::= <Mod> <Type> <Var> <Var List> ';'
        RULE_VARDECL_SEMI4 = 36, // <Var Decl> ::= <Type> <Var> <Var List> ';'
        RULE_VARDECL_SEMI5 = 37, // <Var Decl> ::= <Mod> <Identifier> <Array> <Var> <Var List> ';'
        RULE_VARDECL_SEMI6 = 38, // <Var Decl> ::= <Identifier> <Array> <Var> <Var List> ';'
        RULE_VARDECL_SEMI7 = 39, // <Var Decl> ::= <Mod> <Identifier> <Var> <Var List> ';'
        RULE_VARDECL_SEMI8 = 40, // <Var Decl> ::= <Identifier> <Var> <Var List> ';'
        RULE_VAR = 41, // <Var> ::= <Identifier>
        RULE_VAR_EQ = 42, // <Var> ::= <Identifier> '=' <Op Or>
        RULE_ARRAY_LBRACKET_RBRACKET = 43, // <Array> ::= '[' <Expr> ']'
        RULE_ARRAY_LBRACKET_RBRACKET_LBRACKET_RBRACKET = 44, // <Array> ::= '[' <Expr> ']' '[' <Expr> ']'
        RULE_VARLIST_COMMA = 45, // <Var List> ::= ',' <Var Item> <Var List>
        RULE_VARLIST = 46, // <Var List> ::= 
        RULE_VARITEM = 47, // <Var Item> ::= <Var>
        RULE_MOD_STATIC = 48, // <Mod> ::= static
        RULE_MOD_CONST = 49, // <Mod> ::= const
        RULE_MOD_STATIC_CONST = 50, // <Mod> ::= static const
        RULE_MOD_CONST_STATIC = 51, // <Mod> ::= const static
        RULE_TYPE = 52, // <Type> ::= <Base>
        RULE_BASE = 53, // <Base> ::= <BaseTypes>
        RULE_BASETYPES_ABILCMD = 54, // <BaseTypes> ::= abilcmd
        RULE_BASETYPES_ACTOR = 55, // <BaseTypes> ::= actor
        RULE_BASETYPES_ACTORSCOPE = 56, // <BaseTypes> ::= actorscope
        RULE_BASETYPES_AIFILTER = 57, // <BaseTypes> ::= aifilter
        RULE_BASETYPES_BANK = 58, // <BaseTypes> ::= bank
        RULE_BASETYPES_BOOL = 59, // <BaseTypes> ::= bool
        RULE_BASETYPES_BYTE = 60, // <BaseTypes> ::= byte
        RULE_BASETYPES_CAMERAINFO = 61, // <BaseTypes> ::= camerainfo
        RULE_BASETYPES_CHAR = 62, // <BaseTypes> ::= char
        RULE_BASETYPES_COLOR = 63, // <BaseTypes> ::= color
        RULE_BASETYPES_DOODAD = 64, // <BaseTypes> ::= doodad
        RULE_BASETYPES_FIXED = 65, // <BaseTypes> ::= fixed
        RULE_BASETYPES_INT = 66, // <BaseTypes> ::= int
        RULE_BASETYPES_MARKER = 67, // <BaseTypes> ::= marker
        RULE_BASETYPES_ORDER = 68, // <BaseTypes> ::= order
        RULE_BASETYPES_PLAYERGROUP = 69, // <BaseTypes> ::= playergroup
        RULE_BASETYPES_POINT = 70, // <BaseTypes> ::= point
        RULE_BASETYPES_REGION = 71, // <BaseTypes> ::= region
        RULE_BASETYPES_REVEALER = 72, // <BaseTypes> ::= revealer
        RULE_BASETYPES_SOUND = 73, // <BaseTypes> ::= sound
        RULE_BASETYPES_SOUNDLINK = 74, // <BaseTypes> ::= soundlink
        RULE_BASETYPES_STRING = 75, // <BaseTypes> ::= string
        RULE_BASETYPES_TEXT = 76, // <BaseTypes> ::= text
        RULE_BASETYPES_TIMER = 77, // <BaseTypes> ::= timer
        RULE_BASETYPES_TRANSMISSIONSOURCE = 78, // <BaseTypes> ::= transmissionsource
        RULE_BASETYPES_TRIGGER = 79, // <BaseTypes> ::= trigger
        RULE_BASETYPES_UNIT = 80, // <BaseTypes> ::= unit
        RULE_BASETYPES_UNITFILTER = 81, // <BaseTypes> ::= unitfilter
        RULE_BASETYPES_UNITGROUP = 82, // <BaseTypes> ::= unitgroup
        RULE_BASETYPES_UNITREF = 83, // <BaseTypes> ::= unitref
        RULE_BASETYPES_VOID = 84, // <BaseTypes> ::= void
        RULE_BASETYPES_WAVE = 85, // <BaseTypes> ::= wave
        RULE_BASETYPES_WAVEINFO = 86, // <BaseTypes> ::= waveinfo
        RULE_BASETYPES_WAVETARGET = 87, // <BaseTypes> ::= wavetarget
        RULE_STM = 88, // <Stm> ::= <Var Decl>
        RULE_STM_IF_LPARAN_RPARAN = 89, // <Stm> ::= if '(' <Expr> ')' <Stm>
        RULE_STM_IF_LPARAN_RPARAN_ELSE = 90, // <Stm> ::= if '(' <Expr> ')' <Then Stm> else <Stm>
        RULE_STM_WHILE_LPARAN_RPARAN = 91, // <Stm> ::= while '(' <Expr> ')' <Stm>
        RULE_STM2 = 92, // <Stm> ::= <Normal Stm>
        RULE_THENSTM_IF_LPARAN_RPARAN_ELSE = 93, // <Then Stm> ::= if '(' <Expr> ')' <Then Stm> else <Then Stm>
        RULE_THENSTM_WHILE_LPARAN_RPARAN = 94, // <Then Stm> ::= while '(' <Expr> ')' <Then Stm>
        RULE_THENSTM = 95, // <Then Stm> ::= <Normal Stm>
        RULE_NORMALSTM = 96, // <Normal Stm> ::= <Block>
        RULE_NORMALSTM_SEMI = 97, // <Normal Stm> ::= <Expr> ';'
        RULE_NORMALSTM_BREAK_SEMI = 98, // <Normal Stm> ::= break ';'
        RULE_NORMALSTM_CONTINUE_SEMI = 99, // <Normal Stm> ::= continue ';'
        RULE_NORMALSTM_RETURN_SEMI = 100, // <Normal Stm> ::= return <Expr> ';'
        RULE_NORMALSTM_RETURN_SEMI2 = 101, // <Normal Stm> ::= return ';'
        RULE_NORMALSTM_SEMI2 = 102, // <Normal Stm> ::= ';'
        RULE_BLOCK_LBRACE_RBRACE = 103, // <Block> ::= '{' <Stm List> '}'
        RULE_STMLIST = 104, // <Stm List> ::= <Stm> <Stm List>
        RULE_STMLIST2 = 105, // <Stm List> ::= 
        RULE_EXPR = 106, // <Expr> ::= <Op Assign>
        RULE_OPASSIGN_EQ = 107, // <Op Assign> ::= <Op Or> '=' <Op Assign>
        RULE_OPASSIGN_PLUSEQ = 108, // <Op Assign> ::= <Op Or> '+=' <Op Assign>
        RULE_OPASSIGN_MINUSEQ = 109, // <Op Assign> ::= <Op Or> '-=' <Op Assign>
        RULE_OPASSIGN_TIMESEQ = 110, // <Op Assign> ::= <Op Or> '*=' <Op Assign>
        RULE_OPASSIGN_DIVEQ = 111, // <Op Assign> ::= <Op Or> '/=' <Op Assign>
        RULE_OPASSIGN_CARETEQ = 112, // <Op Assign> ::= <Op Or> '^=' <Op Assign>
        RULE_OPASSIGN_AMPEQ = 113, // <Op Assign> ::= <Op Or> '&=' <Op Assign>
        RULE_OPASSIGN_PIPEEQ = 114, // <Op Assign> ::= <Op Or> '|=' <Op Assign>
        RULE_OPASSIGN_GTGTEQ = 115, // <Op Assign> ::= <Op Or> '>>=' <Op Assign>
        RULE_OPASSIGN_LTLTEQ = 116, // <Op Assign> ::= <Op Or> '<<=' <Op Assign>
        RULE_OPASSIGN = 117, // <Op Assign> ::= <Op Or>
        RULE_OPOR_PIPEPIPE = 118, // <Op Or> ::= <Op Or> '||' <Op And>
        RULE_OPOR = 119, // <Op Or> ::= <Op And>
        RULE_OPAND_AMPAMP = 120, // <Op And> ::= <Op And> '&&' <Op BinOR>
        RULE_OPAND = 121, // <Op And> ::= <Op BinOR>
        RULE_OPBINOR_PIPE = 122, // <Op BinOR> ::= <Op BinOR> '|' <Op BinXOR>
        RULE_OPBINOR = 123, // <Op BinOR> ::= <Op BinXOR>
        RULE_OPBINXOR_CARET = 124, // <Op BinXOR> ::= <Op BinXOR> '^' <Op BinAND>
        RULE_OPBINXOR = 125, // <Op BinXOR> ::= <Op BinAND>
        RULE_OPBINAND_AMP = 126, // <Op BinAND> ::= <Op BinAND> '&' <Op Equate>
        RULE_OPBINAND = 127, // <Op BinAND> ::= <Op Equate>
        RULE_OPEQUATE_EQEQ = 128, // <Op Equate> ::= <Op Equate> '==' <Op Compare>
        RULE_OPEQUATE_EXCLAMEQ = 129, // <Op Equate> ::= <Op Equate> '!=' <Op Compare>
        RULE_OPEQUATE = 130, // <Op Equate> ::= <Op Compare>
        RULE_OPCOMPARE_LT = 131, // <Op Compare> ::= <Op Compare> '<' <Op Shift>
        RULE_OPCOMPARE_GT = 132, // <Op Compare> ::= <Op Compare> '>' <Op Shift>
        RULE_OPCOMPARE_LTEQ = 133, // <Op Compare> ::= <Op Compare> '<=' <Op Shift>
        RULE_OPCOMPARE_GTEQ = 134, // <Op Compare> ::= <Op Compare> '>=' <Op Shift>
        RULE_OPCOMPARE = 135, // <Op Compare> ::= <Op Shift>
        RULE_OPSHIFT_LTLT = 136, // <Op Shift> ::= <Op Shift> '<<' <Op Add>
        RULE_OPSHIFT_GTGT = 137, // <Op Shift> ::= <Op Shift> '>>' <Op Add>
        RULE_OPSHIFT = 138, // <Op Shift> ::= <Op Add>
        RULE_OPADD_PLUS = 139, // <Op Add> ::= <Op Add> '+' <Op Mult>
        RULE_OPADD_MINUS = 140, // <Op Add> ::= <Op Add> '-' <Op Mult>
        RULE_OPADD = 141, // <Op Add> ::= <Op Mult>
        RULE_OPMULT_TIMES = 142, // <Op Mult> ::= <Op Mult> '*' <Op Unary>
        RULE_OPMULT_DIV = 143, // <Op Mult> ::= <Op Mult> '/' <Op Unary>
        RULE_OPMULT_PERCENT = 144, // <Op Mult> ::= <Op Mult> '%' <Op Unary>
        RULE_OPMULT = 145, // <Op Mult> ::= <Op Unary>
        RULE_OPUNARY_EXCLAM = 146, // <Op Unary> ::= '!' <Op Unary>
        RULE_OPUNARY_TILDE = 147, // <Op Unary> ::= '~' <Op Unary>
        RULE_OPUNARY_MINUS = 148, // <Op Unary> ::= '-' <Op Unary>
        RULE_OPUNARY = 149, // <Op Unary> ::= <Op Pointer>
        RULE_OPPOINTER_DOT = 150, // <Op Pointer> ::= <Op Pointer> '.' <Value>
        RULE_OPPOINTER = 151, // <Op Pointer> ::= <Value>
        RULE_VALUE_OCTLITERAL = 152, // <Value> ::= OctLiteral
        RULE_VALUE_HEXLITERAL = 153, // <Value> ::= HexLiteral
        RULE_VALUE_DECLITERAL = 154, // <Value> ::= DecLiteral
        RULE_VALUE_STRINGLITERAL = 155, // <Value> ::= StringLiteral
        RULE_VALUE_FLOATLITERAL = 156, // <Value> ::= FloatLiteral
        RULE_VALUE = 157, // <Value> ::= <Member Access>
        RULE_VALUE_LPARAN_RPARAN = 158, // <Value> ::= '(' <Expr> ')'
        RULE_MEMBERACCESS = 159, // <Member Access> ::= <Identifier>
        RULE_MEMBERACCESS_LPARAN_RPARAN = 160, // <Member Access> ::= <Identifier> '(' ')'
        RULE_MEMBERACCESS2 = 161, // <Member Access> ::= <Identifier> <Array>
        RULE_MEMBERACCESS_LPARAN_RPARAN2 = 162, // <Member Access> ::= <Identifier> '(' <Param Expressions> ')'
        RULE_PARAMEXPRESSIONS_COMMA = 163, // <Param Expressions> ::= <Expr> ',' <Param Expressions>
        RULE_PARAMEXPRESSIONS = 164  // <Param Expressions> ::= <Expr>
    };

    class SkeletonParser {
        static IList<Entity> entities = new List<Entity>();
        List<Token> processedTokens = new List<Token>();
        LALRParser parser;
        static Dictionary<string, int> globalOrderingTable = new Dictionary<string, int>();
        static Dictionary<Entity, int> entitySpecificVariableOrderingTable = new Dictionary<Entity, int>();
        string currentFileName;
        public bool reportErrors;
        public bool valid;

        public static ReadOnlyCollection<Entity> Entities {
            get {
                return new ReadOnlyCollection<Entity>(entities);
            }
        }

        public static void ClearEntities() {
            entities.Clear();
            NamedEntityRegistre.Clear();
            globalOrderingTable.Clear();
            entitySpecificVariableOrderingTable.Clear();
        }

        public string CurrentFileName {
            get {
                return currentFileName;
            }
            set {
                currentFileName = value;
            }
        }

        public SkeletonParser(string filename) {
            FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
            Init(stream);
            stream.Close();
        }

        public SkeletonParser(string baseName, string resourceName) {
            byte[] buffer = ResourceUtil.GetByteArrayResource(Assembly.GetExecutingAssembly(), baseName, resourceName);
            MemoryStream stream = new MemoryStream(buffer);
            Init(stream);
            stream.Close();
        }

        public SkeletonParser(Stream stream) {
            Init(stream);
        }

        private void Init(Stream stream) {
            CGTReader reader = new CGTReader(stream);
            parser = reader.CreateNewParser();
            parser.TrimReductions = false;
            parser.StoreTokens = LALRParser.StoreTokensMode.NoUserObject;

            parser.OnAccept += new LALRParser.AcceptHandler(AcceptEvent);
            parser.OnTokenError += new LALRParser.TokenErrorHandler(TokenErrorEvent);
            parser.OnParseError += new LALRParser.ParseErrorHandler(ParseErrorEvent);
        }

        public void Parse(string source) {
            try {
                parser.Parse(source);
            } catch (Exception) {
                Parse(source);
            }
        }

        private enum StatementType {
            BreakStatement,
            ContinueStatement,
            IfStatement,
            IfElseStatement,
            ReturnStatement,
            WhileStatement
        }

        private class TokenInfo {
            public TerminalToken token;
            public TokenInfo parent;

            public TokenInfo(TerminalToken token, TokenInfo parent) {
                this.token = token;
                this.parent = parent;
            }
        }

        private class EntityWrapper {
            public Entity Entity;
            public EntityWrapper Parent;

            internal EntityWrapper() { }
            internal EntityWrapper(Entity entity, EntityWrapper parent) {
                Entity = entity;
                Parent = parent;
            }
        }

        private void SetEntityDefaultValues(Entity entity) {
            entity.FileName = currentFileName;
        }

        private TypeReference CreateTypeReference(NonterminalToken typeToken) {
            if (typeToken.Rule.Id == (int)RuleConstants.RULE_IDENTIFIER_ID) {
                TypeReference type = new TypeReference();
                type.Type = CreateExpression(typeToken);
                type.Type.Parent = type;
                type.StartLine = type.Type.StartLine;
                type.StartColumn = type.Type.StartColumn;
                type.EndLine = type.Type.EndLine;
                type.EndColumn = type.Type.EndColumn;
                SetEntityDefaultValues(type);
                return type;
            } else {
                if (typeToken.Rule.Id == (int)RuleConstants.RULE_TYPE) {
                    NonterminalToken baseToken = typeToken.Tokens[0] as NonterminalToken;
                    NonterminalToken baseTypesToken = baseToken.Tokens[0] as NonterminalToken;
                    TerminalToken terminalToken = baseTypesToken.Tokens[0] as TerminalToken;
                    TypeReference type = new TypeReference();
                    type.Type = new IdentifierExpression() { Identifier = terminalToken.Text };
                    type.Type.Parent = type;
                    type.StartLine = terminalToken.Location.LineNr;
                    type.StartColumn = terminalToken.Location.ColumnNr;
                    type.EndLine = type.StartLine;
                    type.EndColumn = type.StartColumn + terminalToken.Text.Length;
                    SetEntityDefaultValues(type.Type);
                    SetEntityDefaultValues(type);
                    return type;
                }
            }

            return null;
        }

        private void AddArrayDimensionsToTypeReference(NonterminalToken token, TypeReference type) {
            if (token.Rule.Id == (int)RuleConstants.RULE_ARRAY_LBRACKET_RBRACKET || token.Rule.Id == (int)RuleConstants.RULE_ARRAY_LBRACKET_RBRACKET_LBRACKET_RBRACKET) {
                NonterminalToken firstDimension = token.Tokens[1] as NonterminalToken;
                if (firstDimension != null) {
                    Expression expression = CreateExpression(firstDimension);
                    type.ArrayDimensionExpressions.Add(expression);
                    expression.Parent = type;
                }

                if (token.Rule.Id == (int)RuleConstants.RULE_ARRAY_LBRACKET_RBRACKET_LBRACKET_RBRACKET) {
                    NonterminalToken secondDimension = token.Tokens[4] as NonterminalToken;
                    if (secondDimension != null) {
                        type.ArrayDimensionExpressions.Add(CreateExpression(secondDimension));
                    }
                }
            }
        }

        private void AddParameterExpressions(List<Expression> parameterExpressions, NonterminalToken token) {
            foreach (Token childToken in token.Tokens) {
                if (childToken is NonterminalToken) {
                    NonterminalToken nonterminalToken = childToken as NonterminalToken;
                    if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_EXPR) {
                        Expression expression = CreateExpression(nonterminalToken);
                        parameterExpressions.Add(expression);
                    } else if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_PARAMEXPRESSIONS || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_PARAMEXPRESSIONS_COMMA) {
                        AddParameterExpressions(parameterExpressions, nonterminalToken);
                    }
                }
            }
        }

        private void AddParametersToFunction(Function function, NonterminalToken token) {
            foreach (Token childToken in token.Tokens) {
                NonterminalToken nonterminalToken = childToken as NonterminalToken;
                if (nonterminalToken != null) {
                    if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_PARAM || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_PARAM2) {
                        Variable variable = new Variable();
                        NonterminalToken typeToken = nonterminalToken.Tokens[0] as NonterminalToken;
                        NonterminalToken identifierToken = nonterminalToken.Tokens[1] as NonterminalToken;
                        TerminalToken firstToken = GetFirstInnermostTerminalToken(typeToken);
                        TerminalToken lastToken = GetFirstInnermostTerminalToken(identifierToken);
                        variable.StartLine = firstToken.Location.LineNr;
                        variable.StartColumn = firstToken.Location.ColumnNr;
                        variable.EndLine = lastToken.Location.LineNr;
                        variable.EndColumn = lastToken.Location.ColumnNr;
                        variable.Type = CreateTypeReference(typeToken);
                        variable.Type.Parent = variable;
                        variable.Name = GetIdentifierValue(identifierToken);
                        variable.IsParameter = true;
                        variable.Parent = function;
                        SetEntityDefaultValues(variable);
                        function.Parameters.Add(variable);
                        NamedEntityRegistre.Add(variable.Name, variable);
                    } else if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_PARAMS || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_PARAMS_COMMA) {
                        AddParametersToFunction(function, nonterminalToken);
                    }
                }
            }
        }

        private string GetIdentifierValue(NonterminalToken token) {
            if (token.Rule.Id == (int)RuleConstants.RULE_IDENTIFIER_ID) {
                return ((token.Tokens[0] as TerminalToken).Text);
            }

            return null;
        }

        private Modifiers GetModifiers(TerminalToken token) {
            if (token != null) {
                if (token.Text == "static") {
                    return Modifiers.Static;
                } else if (token.Text == "const") {
                    return Modifiers.Const;
                }
            }

            return Modifiers.None;
        }

        private Modifiers GetModifiers(NonterminalToken token) {
            if (token.Tokens.Length == 1) {
                TerminalToken terminalToken = token.Tokens[0] as TerminalToken;
                if (terminalToken != null) {
                    return GetModifiers(terminalToken);
                }
            } else if (token.Tokens.Length == 2) {
                TerminalToken firstTerminal = token.Tokens[0] as TerminalToken;
                TerminalToken secondTerminal = token.Tokens[1] as TerminalToken;
                Modifiers modifiers = Modifiers.None;
                if (firstTerminal != null) {
                    modifiers |= GetModifiers(firstTerminal);
                }

                if (secondTerminal != null) {
                    modifiers |= GetModifiers(secondTerminal);
                }

                return modifiers;
            }

            return Modifiers.None;
        }

        private TerminalToken GetFirstInnermostTerminalToken(NonterminalToken nonterminalToken) {
            foreach (Token token in nonterminalToken.Tokens) {
                if (token is NonterminalToken) {
                    TerminalToken terminalToken = GetFirstInnermostTerminalToken((NonterminalToken)token);
                    if (terminalToken != null) {
                        return terminalToken;
                    }
                }

                if (token is TerminalToken) {
                    return ((TerminalToken)token);
                }
            }

            return null;
        }

        TerminalToken lastToken = null;
        private TerminalToken _GetLastInnermostTerminalToken(NonterminalToken nonterminalToken) {
            foreach (Token token in nonterminalToken.Tokens) {
                if (token is NonterminalToken) {
                    TerminalToken terminalToken = _GetLastInnermostTerminalToken((NonterminalToken)token);
                    if (terminalToken != null) {
                        return terminalToken;
                    }
                }

                if (token is TerminalToken) {
                    lastToken = token as TerminalToken;
                }
            }

            return null;
        }

        private TerminalToken GetLastInnermostTerminalToken(NonterminalToken nonterminalToken) {
            lastToken = null;
            _GetLastInnermostTerminalToken(nonterminalToken);
            return lastToken;
        }

        private NonterminalToken GetBlockToken(NonterminalToken nonterminalToken) {
            foreach (Token token in nonterminalToken.Tokens) {
                if (token is NonterminalToken) {
                    NonterminalToken childToken = token as NonterminalToken;
                    if (childToken.Rule.Id == (int)RuleConstants.RULE_BLOCK_LBRACE_RBRACE) {
                        return childToken;
                    } else {
                        return GetBlockToken(childToken);
                    }
                }
            }

            return null;
        }

        private Function CreateFunction(NonterminalToken token, bool isNative, bool isPrototype) {
            NonterminalToken funcDeclToken = null;
            if (token.Rule.Id != (int)RuleConstants.RULE_FUNCDECL_LPARAN_RPARAN && token.Rule.Id != (int)RuleConstants.RULE_FUNCDECL_LPARAN_RPARAN2 && token.Rule.Id != (int)RuleConstants.RULE_FUNCPROTO_LPARAN_RPARAN_SEMI && token.Rule.Id != (int)RuleConstants.RULE_FUNCPROTO_LPARAN_RPARAN_SEMI2 && token.Rule.Id != (int)RuleConstants.RULE_NATIVEDECL_NATIVE_LPARAN_RPARAN_SEMI && token.Rule.Id != (int)RuleConstants.RULE_NATIVEDECL_NATIVE_LPARAN_RPARAN_SEMI2) {
                funcDeclToken = token.Tokens[0] as NonterminalToken;
            } else {
                funcDeclToken = token;
            }

            if (funcDeclToken != null) {
                Function function = new Function();
                function.IsPrototype = isPrototype;
                function.IsNative = isNative;
                if (!globalOrderingTable.ContainsKey(currentFileName)) {
                    globalOrderingTable[currentFileName] = 0;
                }

                function.OrderIndex = globalOrderingTable[currentFileName];
                globalOrderingTable[currentFileName]++;
                int i = isNative ? 1 : 0;
                NonterminalToken funcToken = funcDeclToken.Tokens[i] as NonterminalToken;
                if (funcToken != null) {
                    TerminalToken firstToken = funcToken.Tokens[0] is TerminalToken ? funcToken.Tokens[0] as TerminalToken : GetFirstInnermostTerminalToken(funcToken.Tokens[0] as NonterminalToken);
                    TerminalToken lastToken = funcDeclToken.Tokens[funcDeclToken.Tokens.Length - 1] is NonterminalToken ? ((NonterminalToken)funcDeclToken.Tokens[funcDeclToken.Tokens.Length - 1]).Tokens[((NonterminalToken)funcDeclToken.Tokens[funcDeclToken.Tokens.Length - 1]).Tokens.Length - 1] as TerminalToken : funcDeclToken.Tokens[funcDeclToken.Tokens.Length - 1] as TerminalToken;
                    function.StartLine = firstToken.Location.LineNr;
                    function.StartColumn = firstToken.Location.ColumnNr;
                    function.EndLine = lastToken.Location.LineNr;
                    function.EndColumn = lastToken.Location.ColumnNr;
                    int startArrayIndex = 0;
                    NonterminalToken modToken = funcToken.Tokens[0] as NonterminalToken;
                    if (modToken != null && (modToken.Rule.Id == (int)RuleConstants.RULE_MOD_CONST || modToken.Rule.Id == (int)RuleConstants.RULE_MOD_STATIC || modToken.Rule.Id == (int)RuleConstants.RULE_MOD_CONST_STATIC || modToken.Rule.Id == (int)RuleConstants.RULE_MOD_STATIC_CONST)) {
                        startArrayIndex = 1;
                        Modifiers modifiers = GetModifiers(modToken);
                        function.Modifiers = modifiers;
                    }

                    NonterminalToken typeToken = funcToken.Tokens[startArrayIndex] as NonterminalToken;
                    NonterminalToken arrayToken = funcToken.Tokens[startArrayIndex + 1] as NonterminalToken;
                    int nameTokenIndex = 1;
                    if (arrayToken != null && (arrayToken.Rule.Id == (int)RuleConstants.RULE_ARRAY_LBRACKET_RBRACKET || arrayToken.Rule.Id == (int)RuleConstants.RULE_ARRAY_LBRACKET_RBRACKET_LBRACKET_RBRACKET)) {
                        nameTokenIndex = 2;
                    }

                    function.Type = CreateTypeReference(typeToken);
                    function.Type.Parent = function;
                    if (arrayToken != null && function.Type != null) {
                        AddArrayDimensionsToTypeReference(arrayToken, function.Type);
                    }

                    NonterminalToken identifierToken = funcToken.Tokens[startArrayIndex + nameTokenIndex] as NonterminalToken;
                    function.Name = GetIdentifierValue(identifierToken);
                }

                NonterminalToken paramsToken = funcDeclToken.Tokens[i + 2] as NonterminalToken;
                if (paramsToken != null) {
                    AddParametersToFunction(function, paramsToken);
                }

                if (!isPrototype) {
                    NonterminalToken blockToken = funcDeclToken.Tokens[i + 4 - (paramsToken == null ? 1 : 0)] as NonterminalToken;
                    if (blockToken != null && blockToken.Rule.Id == (int)RuleConstants.RULE_BLOCK_LBRACE_RBRACE) {
                        processedTokens.Add(blockToken);
                        ProcessStatementList(function, blockToken.Tokens[1] as NonterminalToken);
                    }
                }

                SetEntityDefaultValues(function);
                NamedEntityRegistre.Add(function.Name, function);
                return function;
            }

            return null;
        }

        private Variable CreateVariable(NonterminalToken token) {
            NonterminalToken varDeclToken = null;
            if (token.Rule.Id != (int)RuleConstants.RULE_VARDECL_SEMI && token.Rule.Id != (int)RuleConstants.RULE_VARDECL_SEMI2 && token.Rule.Id != (int)RuleConstants.RULE_VARDECL_SEMI3 && token.Rule.Id != (int)RuleConstants.RULE_VARDECL_SEMI4 && token.Rule.Id != (int)RuleConstants.RULE_VARDECL_SEMI5 && token.Rule.Id != (int)RuleConstants.RULE_VARDECL_SEMI6 && token.Rule.Id != (int)RuleConstants.RULE_VARDECL_SEMI7 && token.Rule.Id != (int)RuleConstants.RULE_VARDECL_SEMI8) {
                varDeclToken = token.Tokens[0] as NonterminalToken;
            } else {
                varDeclToken = token;
            }

            if (varDeclToken != null) {
                Variable variable = new Variable();
                int startArrayIndex = 0;
                NonterminalToken modToken = varDeclToken.Tokens[0] as NonterminalToken;
                if (modToken != null && (modToken.Rule.Id == (int)RuleConstants.RULE_MOD_CONST || modToken.Rule.Id == (int)RuleConstants.RULE_MOD_STATIC || modToken.Rule.Id == (int)RuleConstants.RULE_MOD_CONST_STATIC || modToken.Rule.Id == (int)RuleConstants.RULE_MOD_STATIC_CONST)) {
                    startArrayIndex = 1;
                    Modifiers modifiers = GetModifiers(modToken);
                    variable.Modifiers = modifiers;
                }

                NonterminalToken typeToken = varDeclToken.Tokens[startArrayIndex] as NonterminalToken;
                NonterminalToken arrayToken = varDeclToken.Tokens[startArrayIndex + 1] as NonterminalToken;
                NonterminalToken varToken = null;
                if (arrayToken != null && (arrayToken.Rule.Id == (int)RuleConstants.RULE_VAR || arrayToken.Rule.Id == (int)RuleConstants.RULE_VAR_EQ)) {
                    arrayToken = null;
                    varToken = varDeclToken.Tokens[startArrayIndex + 1] as NonterminalToken;
                } else {
                    varToken = varDeclToken.Tokens[startArrayIndex + 2] as NonterminalToken;
                }

                TerminalToken firstToken = varDeclToken.Tokens[0] is TerminalToken ? varDeclToken.Tokens[0] as TerminalToken : GetFirstInnermostTerminalToken(varDeclToken.Tokens[0] as NonterminalToken);
                TerminalToken lastToken = varDeclToken.Tokens[varDeclToken.Tokens.Length - 1] as TerminalToken;
                variable.StartLine = firstToken.Location.LineNr;
                variable.StartColumn = firstToken.Location.ColumnNr;
                variable.EndLine = lastToken.Location.LineNr;
                variable.EndColumn = lastToken.Location.ColumnNr;
                variable.Type = CreateTypeReference(typeToken);
                variable.Type.Parent = variable;
                if (arrayToken != null && variable.Type != null) {
                    AddArrayDimensionsToTypeReference(arrayToken, variable.Type);
                }

                variable.Name = GetIdentifierValue(varToken.Tokens[0] as NonterminalToken);
                if (varToken.Tokens.Length > 1) {
                    variable.Value = CreateExpression(varToken.Tokens[2] as NonterminalToken);
                    variable.Value.Parent = variable;
                }

                SetEntityDefaultValues(variable);
                NamedEntityRegistre.Add(variable.Name, variable);
                return variable;
            }

            return null;
        }

        private void AddVariablesToStruct(Struct s, NonterminalToken structDefToken) {
            foreach (Token token in structDefToken.Tokens) {
                NonterminalToken nonterminalToken = token as NonterminalToken;
                if (nonterminalToken != null) {
                    if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_VARDECL_SEMI || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_VARDECL_SEMI2 || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_VARDECL_SEMI3 || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_VARDECL_SEMI4 || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_VARDECL_SEMI5 || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_VARDECL_SEMI6 || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_VARDECL_SEMI7 || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_VARDECL_SEMI8) {
                        Variable variable = CreateVariable(nonterminalToken);
                        variable.Parent = s;
                    } else if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STRUCTDEF || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STRUCTDEF2) {
                        AddVariablesToStruct(s, nonterminalToken);
                    }
                }
            }
        }

        private Struct CreateStruct(NonterminalToken token) {
            NonterminalToken structDeclToken = null;
            if (token.Rule.Id != (int)RuleConstants.RULE_STRUCTDECL_STRUCT_LBRACE_RBRACE_SEMI) {
                structDeclToken = token.Tokens[0] as NonterminalToken;
            } else {
                structDeclToken = token;
            }

            if (structDeclToken != null) {
                Struct s = new Struct();
                if (!globalOrderingTable.ContainsKey(currentFileName)) {
                    globalOrderingTable[currentFileName] = 0;
                }

                s.OrderIndex = globalOrderingTable[currentFileName];
                globalOrderingTable[currentFileName]++;
                TerminalToken firstToken = structDeclToken.Tokens[0] as TerminalToken;
                s.IsPrototype = true;
                NonterminalToken identifierToken = structDeclToken.Tokens[1] as NonterminalToken;
                s.Name = GetIdentifierValue(identifierToken);
                NonterminalToken structDefToken = structDeclToken.Tokens[3] as NonterminalToken;
                TerminalToken lastToken = structDeclToken.Tokens[structDeclToken.Tokens.Length - 1] as TerminalToken;
                s.StartLine = firstToken.Location.LineNr;
                s.StartColumn = firstToken.Location.ColumnNr;
                s.EndLine = lastToken.Location.LineNr;
                s.EndColumn = lastToken.Location.ColumnNr;
                if (structDefToken != null) {
                    s.IsPrototype = false;
                    processedTokens.Add(structDefToken);
                    AddVariablesToStruct(s, structDefToken);
                }

                SetEntityDefaultValues(s);
                NamedEntityRegistre.Add(s.Name, s);
                return s;
            }

            return null;
        }

        private Include CreateInclude(NonterminalToken token) {
            NonterminalToken includeDeclToken = null;
            if (token.Rule.Id != (int)RuleConstants.RULE_INCLUDEDECL_INCLUDE_STRINGLITERAL) {
                includeDeclToken = token.Tokens[0] as NonterminalToken;
            } else {
                includeDeclToken = token;
            }

            if (includeDeclToken != null) {
                Include include = new Include();
                TerminalToken firstToken = includeDeclToken.Tokens[0] as TerminalToken;
                TerminalToken includedPathToken = includeDeclToken.Tokens[1] as TerminalToken;
                include.IncludedPath = includedPathToken.Text;
                if (System.IO.Path.GetExtension(include.IncludedPath.Replace("\"", "")) == "") {
                    include.IncludedPath = "\"" + include.IncludedPath.Replace("\"", "") + ".galaxy\"";
                }

                include.StartLine = firstToken.Location.LineNr;
                include.StartColumn = firstToken.Location.ColumnNr;
                include.EndLine = includedPathToken.Location.LineNr;
                include.EndColumn = includedPathToken.Location.ColumnNr;
                SetEntityDefaultValues(include);
                NamedEntityRegistre.Add(include.IncludedPath, include);
                return include;
            }

            return null;
        }

        private Typedef CreateTypedef(NonterminalToken token) {
            NonterminalToken typedefDeclToken = null;
            if (token.Rule.Id != (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI & token.Rule.Id != (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI2 && token.Rule.Id != (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI3 && token.Rule.Id != (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI4) {
                typedefDeclToken = token.Tokens[0] as NonterminalToken;
            } else {
                typedefDeclToken = token;
            }

            if (typedefDeclToken != null) {
                Typedef typedef = new Typedef();
                if (!globalOrderingTable.ContainsKey(currentFileName)) {
                    globalOrderingTable[currentFileName] = 0;
                }

                typedef.OrderIndex = globalOrderingTable[currentFileName];
                globalOrderingTable[currentFileName]++;
                TerminalToken firstToken = typedefDeclToken.Tokens[0] as TerminalToken;
                TerminalToken lastToken = typedefDeclToken.Tokens[typedefDeclToken.Tokens.Length - 1] as TerminalToken;
                typedef.StartLine = firstToken.Location.LineNr;
                typedef.StartColumn = firstToken.Location.ColumnNr;
                typedef.EndLine = lastToken.Location.LineNr;
                typedef.EndColumn = lastToken.Location.ColumnNr;
                switch (typedefDeclToken.Rule.Id) {
                    case (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI:
                    case (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI2:
                        NonterminalToken typeToken = typedefDeclToken.Tokens[1] as NonterminalToken;
                        NonterminalToken arrayToken = typedefDeclToken.Tokens[2] as NonterminalToken;
                        NonterminalToken identifierToken = typedefDeclToken.Tokens[3] as NonterminalToken;
                        typedef.OriginalType = CreateTypeReference(typeToken);
                        if (typedef.OriginalType != null) {
                            AddArrayDimensionsToTypeReference(arrayToken, typedef.OriginalType);
                        }

                        typedef.CreatedType = CreateExpression(identifierToken);
                        break;
                    case (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI3:
                    case (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI4:
                        typeToken = typedefDeclToken.Tokens[1] as NonterminalToken;
                        identifierToken = typedefDeclToken.Tokens[2] as NonterminalToken;
                        typedef.OriginalType = CreateTypeReference(typeToken);
                        typedef.CreatedType = CreateExpression(identifierToken);
                        break;
                }

                if (typedef.OriginalType != null) {
                    typedef.OriginalType.Parent = typedef;
                }

                if (typedef.CreatedType != null) {
                    typedef.CreatedType.Parent = typedef;
                }

                SetEntityDefaultValues(typedef);
                NamedEntityRegistre.Add(((IdentifierExpression)typedef.CreatedType).Identifier, typedef);
                return typedef;
            }

            return null;
        }

        private Expression CreateExpression(NonterminalToken token) {
            if (token != null) {
                Expression expression = null;
                TerminalToken firstToken = null;
                TerminalToken lastToken = null;
                bool handled = false;
                if (token.Tokens.Length > 1 || (token.Tokens.Length == 1 && token.Tokens[0] is TerminalToken)) {
                    switch (token.Rule.Id) {
                        case (int)RuleConstants.RULE_OPADD:
                        case (int)RuleConstants.RULE_OPADD_MINUS:
                        case (int)RuleConstants.RULE_OPADD_PLUS:
                            AddExpression addExpression = new AddExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            addExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            addExpression.Left.Parent = addExpression;
                            addExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            addExpression.Right.Parent = addExpression;
                            switch (token.Rule.Id) {
                                case (int)RuleConstants.RULE_OPADD_MINUS:
                                    addExpression.Type = AddExpression.ExpressionType.Subtract;
                                    break;
                                case (int)RuleConstants.RULE_OPADD_PLUS:
                                    addExpression.Type = AddExpression.ExpressionType.Add;
                                    break;
                            }

                            expression = addExpression;
                            break;
                        case (int)RuleConstants.RULE_OPAND:
                        case (int)RuleConstants.RULE_OPAND_AMPAMP:
                            ConditionExpression conditionExpression = new ConditionExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            conditionExpression.Left.Parent = conditionExpression;
                            conditionExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Right.Parent = conditionExpression;
                            conditionExpression.Type = ConditionExpression.ExpressionType.And;
                            expression = conditionExpression;
                            break;
                        case (int)RuleConstants.RULE_OPASSIGN:
                        case (int)RuleConstants.RULE_OPASSIGN_AMPEQ:
                        case (int)RuleConstants.RULE_OPASSIGN_CARETEQ:
                        case (int)RuleConstants.RULE_OPASSIGN_DIVEQ:
                        case (int)RuleConstants.RULE_OPASSIGN_EQ:
                        case (int)RuleConstants.RULE_OPASSIGN_GTGTEQ:
                        case (int)RuleConstants.RULE_OPASSIGN_LTLTEQ:
                        case (int)RuleConstants.RULE_OPASSIGN_MINUSEQ:
                        case (int)RuleConstants.RULE_OPASSIGN_PIPEEQ:
                        case (int)RuleConstants.RULE_OPASSIGN_PLUSEQ:
                        case (int)RuleConstants.RULE_OPASSIGN_TIMESEQ:
                            AssignExpression assignExpression = new AssignExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            assignExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            assignExpression.Left.Parent = assignExpression;
                            assignExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            assignExpression.Right.Parent = assignExpression;
                            switch (token.Rule.Id) {
                                case (int)RuleConstants.RULE_OPASSIGN_AMPEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.AmpAssign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_CARETEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.PowerAssign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_DIVEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.DivideAssign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_EQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.Assign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_GTGTEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.ShiftRightAssign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_LTLTEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.ShiftLeftAssign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_MINUSEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.SubtractAssign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_PIPEEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.BarAssign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_PLUSEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.AddAssign;
                                    break;
                                case (int)RuleConstants.RULE_OPASSIGN_TIMESEQ:
                                    assignExpression.Type = AssignExpression.ExpressionType.MultiplyAssign;
                                    break;
                            }

                            expression = assignExpression;
                            break;
                        case (int)RuleConstants.RULE_OPBINAND:
                        case (int)RuleConstants.RULE_OPBINAND_AMP:
                            conditionExpression = new ConditionExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            conditionExpression.Left.Parent = conditionExpression;
                            conditionExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Right.Parent = conditionExpression;
                            conditionExpression.Type = ConditionExpression.ExpressionType.BinaryAnd;
                            expression = conditionExpression;
                            break;
                        case (int)RuleConstants.RULE_OPBINOR:
                        case (int)RuleConstants.RULE_OPBINOR_PIPE:
                            conditionExpression = new ConditionExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            conditionExpression.Left.Parent = conditionExpression;
                            conditionExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Right.Parent = conditionExpression;
                            conditionExpression.Type = ConditionExpression.ExpressionType.BinaryOr;
                            expression = conditionExpression;
                            break;
                        case (int)RuleConstants.RULE_OPBINXOR:
                        case (int)RuleConstants.RULE_OPBINXOR_CARET:
                            conditionExpression = new ConditionExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            conditionExpression.Left.Parent = conditionExpression;
                            conditionExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Right.Parent = conditionExpression;
                            conditionExpression.Type = ConditionExpression.ExpressionType.BinaryXor;
                            expression = conditionExpression;
                            break;
                        case (int)RuleConstants.RULE_OPCOMPARE:
                        case (int)RuleConstants.RULE_OPCOMPARE_GT:
                        case (int)RuleConstants.RULE_OPCOMPARE_GTEQ:
                        case (int)RuleConstants.RULE_OPCOMPARE_LT:
                        case (int)RuleConstants.RULE_OPCOMPARE_LTEQ:
                            CompareExpression compareExpression = new CompareExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            compareExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            compareExpression.Left.Parent = compareExpression;
                            compareExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            compareExpression.Right.Parent = compareExpression;
                            switch (token.Rule.Id) {
                                case (int)RuleConstants.RULE_OPCOMPARE_GT:
                                    compareExpression.Type = CompareExpression.ExpressionType.GreaterThan;
                                    break;
                                case (int)RuleConstants.RULE_OPCOMPARE_GTEQ:
                                    compareExpression.Type = CompareExpression.ExpressionType.GreaterThanOrEqual;
                                    break;
                                case (int)RuleConstants.RULE_OPCOMPARE_LT:
                                    compareExpression.Type = CompareExpression.ExpressionType.LessThan;
                                    break;
                                case (int)RuleConstants.RULE_OPCOMPARE_LTEQ:
                                    compareExpression.Type = CompareExpression.ExpressionType.LessThanOrEqual;
                                    break;
                            }

                            expression = compareExpression;
                            break;
                        case (int)RuleConstants.RULE_OPEQUATE:
                        case (int)RuleConstants.RULE_OPEQUATE_EQEQ:
                        case (int)RuleConstants.RULE_OPEQUATE_EXCLAMEQ:
                            EquateExpression equateExpression = new EquateExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            equateExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            equateExpression.Left.Parent = equateExpression;
                            equateExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            equateExpression.Right.Parent = equateExpression;
                            switch (token.Rule.Id) {
                                case (int)RuleConstants.RULE_OPEQUATE_EQEQ:
                                    equateExpression.Type = EquateExpression.ExpressionType.Equal;
                                    break;
                                case (int)RuleConstants.RULE_OPEQUATE_EXCLAMEQ:
                                    equateExpression.Type = EquateExpression.ExpressionType.NotEqual;
                                    break;
                            }

                            expression = equateExpression;
                            break;
                        case (int)RuleConstants.RULE_OPMULT:
                        case (int)RuleConstants.RULE_OPMULT_DIV:
                        case (int)RuleConstants.RULE_OPMULT_PERCENT:
                        case (int)RuleConstants.RULE_OPMULT_TIMES:
                            MultiplyExpression multiplyExpression = new MultiplyExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            multiplyExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            multiplyExpression.Left.Parent = multiplyExpression;
                            multiplyExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            multiplyExpression.Right.Parent = multiplyExpression;
                            switch (token.Rule.Id) {
                                case (int)RuleConstants.RULE_OPMULT_DIV:
                                    multiplyExpression.Type = MultiplyExpression.ExpressionType.Divide;
                                    break;
                                case (int)RuleConstants.RULE_OPMULT_PERCENT:
                                    multiplyExpression.Type = MultiplyExpression.ExpressionType.Mod;
                                    break;
                                case (int)RuleConstants.RULE_OPMULT_TIMES:
                                    multiplyExpression.Type = MultiplyExpression.ExpressionType.Multiply;
                                    break;
                            }

                            expression = multiplyExpression;
                            break;
                        case (int)RuleConstants.RULE_OPOR:
                        case (int)RuleConstants.RULE_OPOR_PIPEPIPE:
                            conditionExpression = new ConditionExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            conditionExpression.Left.Parent = conditionExpression;
                            conditionExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            conditionExpression.Right.Parent = conditionExpression;
                            conditionExpression.Type = ConditionExpression.ExpressionType.Or;
                            expression = conditionExpression;
                            break;
                        case (int)RuleConstants.RULE_OPPOINTER:
                        case (int)RuleConstants.RULE_OPPOINTER_DOT:
                            PointerExpression pointerExpression = new PointerExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            pointerExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            pointerExpression.Left.Parent = pointerExpression;
                            pointerExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            pointerExpression.Right.Parent = pointerExpression;
                            pointerExpression.Type = PointerExpression.ExpressionType.MemberAccess;
                            expression = pointerExpression;
                            break;
                        case (int)RuleConstants.RULE_OPSHIFT:
                        case (int)RuleConstants.RULE_OPSHIFT_GTGT:
                        case (int)RuleConstants.RULE_OPSHIFT_LTLT:
                            ShiftExpression shiftExpression = new ShiftExpression();
                            firstToken = GetFirstInnermostTerminalToken(token.Tokens[0] as NonterminalToken);
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[2] as NonterminalToken);
                            shiftExpression.Left = CreateExpression(token.Tokens[0] as NonterminalToken);
                            shiftExpression.Left.Parent = shiftExpression;
                            shiftExpression.Right = CreateExpression(token.Tokens[2] as NonterminalToken);
                            shiftExpression.Right.Parent = shiftExpression;
                            switch (token.Rule.Id) {
                                case (int)RuleConstants.RULE_OPSHIFT_GTGT:
                                    shiftExpression.Type = ShiftExpression.ExpressionType.ShiftRight;
                                    break;
                                case (int)RuleConstants.RULE_OPSHIFT_LTLT:
                                    shiftExpression.Type = ShiftExpression.ExpressionType.ShiftLeft;
                                    break;
                            }

                            expression = shiftExpression;
                            break;
                        case (int)RuleConstants.RULE_OPUNARY:
                        case (int)RuleConstants.RULE_OPUNARY_EXCLAM:
                        case (int)RuleConstants.RULE_OPUNARY_MINUS:
                        case (int)RuleConstants.RULE_OPUNARY_TILDE:
                            UnaryExpression unaryExpression = new UnaryExpression();
                            firstToken = token.Tokens[0] as TerminalToken;
                            lastToken = GetLastInnermostTerminalToken(token.Tokens[1] as NonterminalToken);
                            unaryExpression.Value = CreateExpression(token.Tokens[1] as NonterminalToken);
                            unaryExpression.Value.Parent = unaryExpression;
                            switch (token.Rule.Id) {
                                case (int)RuleConstants.RULE_OPUNARY_EXCLAM:
                                    unaryExpression.Type = UnaryExpression.ExpressionType.NegateBool;
                                    break;
                                case (int)RuleConstants.RULE_OPUNARY_MINUS:
                                    unaryExpression.Type = UnaryExpression.ExpressionType.NegateNumber;
                                    break;
                                case (int)RuleConstants.RULE_OPUNARY_TILDE:
                                    unaryExpression.Type = UnaryExpression.ExpressionType.ReverseBits;
                                    break;
                            }

                            expression = unaryExpression;
                            break;
                        case (int)RuleConstants.RULE_VALUE:
                        case (int)RuleConstants.RULE_VALUE_DECLITERAL:
                        case (int)RuleConstants.RULE_VALUE_FLOATLITERAL:
                        case (int)RuleConstants.RULE_VALUE_HEXLITERAL:
                        case (int)RuleConstants.RULE_VALUE_LPARAN_RPARAN:
                        case (int)RuleConstants.RULE_VALUE_OCTLITERAL:
                        case (int)RuleConstants.RULE_VALUE_STRINGLITERAL:
                            ValueExpression valueExpression = new ValueExpression();
                            NonterminalToken valueToken = token.Tokens[0] as NonterminalToken;
                            handled = true;
                            if (valueToken != null) {
                                valueExpression.Value = CreateExpression(valueToken);
                                valueExpression.StartLine = valueExpression.Value.StartLine;
                                valueExpression.StartColumn = valueExpression.Value.StartColumn;
                                valueExpression.EndLine = valueExpression.Value.EndLine;
                                valueExpression.EndColumn = valueExpression.Value.EndColumn;
                                valueExpression.Value.Parent = valueExpression;
                            } else if (token.Tokens[0] is TerminalToken) {
                                TerminalToken terminalToken = token.Tokens[0] as TerminalToken;
                                if (terminalToken.Text != "(") {
                                    IdentifierExpression value = new IdentifierExpression();
                                    value.Identifier = terminalToken.Text;
                                    value.StartLine = terminalToken.Location.LineNr;
                                    value.StartColumn = terminalToken.Location.ColumnNr;
                                    value.EndLine = terminalToken.Location.LineNr;
                                    value.EndColumn = terminalToken.Location.ColumnNr + terminalToken.Text.Length;
                                    valueExpression.Value = value;
                                    valueExpression.StartLine = value.StartLine;
                                    valueExpression.StartColumn = value.StartColumn;
                                    valueExpression.EndLine = value.EndLine;
                                    valueExpression.EndColumn = value.EndColumn;
                                    valueExpression.Value.Parent = valueExpression;
                                }
                            }

                            switch (token.Rule.Id) {
                                case (int)RuleConstants.RULE_VALUE_DECLITERAL:
                                    valueExpression.Type = ValueExpression.ExpressionType.DecLiteral;
                                    break;
                                case (int)RuleConstants.RULE_VALUE_FLOATLITERAL:
                                    valueExpression.Type = ValueExpression.ExpressionType.FloatLiteral;
                                    break;
                                case (int)RuleConstants.RULE_VALUE_HEXLITERAL:
                                    valueExpression.Type = ValueExpression.ExpressionType.HexLiteral;
                                    break;
                                case (int)RuleConstants.RULE_VALUE_LPARAN_RPARAN:
                                    valueExpression.ChildExpression = CreateExpression(token.Tokens[1] as NonterminalToken);
                                    firstToken = token.Tokens[0] as TerminalToken;
                                    lastToken = token.Tokens[2] as TerminalToken;
                                    valueExpression.StartLine = firstToken.Location.LineNr;
                                    valueExpression.StartColumn = firstToken.Location.ColumnNr;
                                    valueExpression.EndLine = lastToken.Location.LineNr;
                                    valueExpression.EndColumn = lastToken.Location.ColumnNr;
                                    valueExpression.ChildExpression.Parent = valueExpression;
                                    valueExpression.Type = ValueExpression.ExpressionType.ExpressionEncapsulation;
                                    break;
                                case (int)RuleConstants.RULE_VALUE_OCTLITERAL:
                                    valueExpression.Type = ValueExpression.ExpressionType.OctLiteral;
                                    break;
                                case (int)RuleConstants.RULE_VALUE_STRINGLITERAL:
                                    valueExpression.Type = ValueExpression.ExpressionType.StringLiteral;
                                    break;
                            }

                            expression = valueExpression;
                            break;
                        case (int)RuleConstants.RULE_MEMBERACCESS:
                        case (int)RuleConstants.RULE_MEMBERACCESS_LPARAN_RPARAN:
                        case (int)RuleConstants.RULE_MEMBERACCESS_LPARAN_RPARAN2:
                        case (int)RuleConstants.RULE_MEMBERACCESS2: {
                                MemberAccessExpression memberAccessExpression = new MemberAccessExpression();
                                NonterminalToken nonterminalToken = token.Tokens[0] as NonterminalToken;
                                firstToken = GetFirstInnermostTerminalToken(nonterminalToken);
                                lastToken = token.Tokens[token.Tokens.Length - 1] is NonterminalToken ? GetFirstInnermostTerminalToken(token.Tokens[token.Tokens.Length - 1] as NonterminalToken) : token.Tokens[token.Tokens.Length - 1] as TerminalToken;
                                memberAccessExpression.Member = CreateExpression(nonterminalToken);
                                memberAccessExpression.Member.Parent = memberAccessExpression;
                                memberAccessExpression.Type = MemberAccessExpression.ExpressionType.VariableAccess;
                                switch (token.Rule.Id) {
                                    case (int)RuleConstants.RULE_MEMBERACCESS_LPARAN_RPARAN:
                                        memberAccessExpression.Type = MemberAccessExpression.ExpressionType.FunctionCall;
                                        break;
                                    case (int)RuleConstants.RULE_MEMBERACCESS_LPARAN_RPARAN2:
                                        memberAccessExpression.Type = MemberAccessExpression.ExpressionType.FunctionCall;
                                        AddParameterExpressions(memberAccessExpression.ParameterExpressions, token.Tokens[2] as NonterminalToken);
                                        foreach (Expression param in memberAccessExpression.ParameterExpressions) {
                                            param.Parent = memberAccessExpression;
                                        }

                                        break;
                                    case (int)RuleConstants.RULE_MEMBERACCESS2:
                                        memberAccessExpression.Type = MemberAccessExpression.ExpressionType.VariableAccess;
                                        TypeReference dummyTypeReference = new TypeReference();
                                        AddArrayDimensionsToTypeReference(token.Tokens[1] as NonterminalToken, dummyTypeReference);
                                        dummyTypeReference.ArrayDimensionExpressions.ForEach(expr => memberAccessExpression.ArrayDimensionExpressions.Add(expr));
                                        break;
                                }

                                expression = memberAccessExpression;
                                break;
                            }
                        case (int)RuleConstants.RULE_IDENTIFIER_ID:
                            IdentifierExpression identifierExpression = new IdentifierExpression();
                            TerminalToken textToken = token.Tokens[0] as TerminalToken;
                            identifierExpression.Identifier = textToken.Text;
                            identifierExpression.StartLine = textToken.Location.LineNr;
                            identifierExpression.StartColumn = textToken.Location.ColumnNr;
                            identifierExpression.EndLine = textToken.Location.LineNr;
                            identifierExpression.EndColumn = textToken.Location.ColumnNr + textToken.Text.Length;
                            handled = true;
                            expression = identifierExpression;
                            break;
                    }
                } else {
                    expression = CreateExpression(token.Tokens[0] as NonterminalToken);
                }

                if (expression != null) {
                    SetEntityDefaultValues(expression);
                }

                if (firstToken != null && lastToken != null && !handled) {
                    expression.StartLine = firstToken.Location.LineNr;
                    expression.StartColumn = firstToken.Location.ColumnNr;
                    if (firstToken == lastToken) {
                        expression.EndLine = firstToken.Location.LineNr;
                        expression.EndColumn = firstToken.Location.ColumnNr + firstToken.Text.Length;
                    } else {
                        expression.EndLine = lastToken.Location.LineNr;
                        expression.EndColumn = lastToken.Location.ColumnNr;
                    }
                }

                return expression;
            }

            return null;
        }

        private Statement CreateStatement(NonterminalToken token, StatementType type) {
            if (token != null) {
                Statement statement = null;
                BreakStatement breakStatement = null;
                ContinueStatement continueStatement = null;
                IfStatement ifStatement = null;
                ElseStatement elseStatement = null;
                ReturnStatement returnStatement = null;
                WhileStatement whileStatement = null;
                TerminalToken firstToken = null;
                TerminalToken lastToken = null;
                bool handled = false;
                switch (type) {
                    case StatementType.BreakStatement:
                        statement = new BreakStatement();
                        breakStatement = statement as BreakStatement;
                        firstToken = token.Tokens[0] as TerminalToken;
                        lastToken = token.Tokens[1] as TerminalToken;
                        break;
                    case StatementType.ContinueStatement:
                        statement = new ContinueStatement();
                        continueStatement = statement as ContinueStatement;
                        firstToken = token.Tokens[0] as TerminalToken;
                        lastToken = token.Tokens[1] as TerminalToken;
                        break;
                    case StatementType.IfElseStatement:
                        statement = new IfStatement();
                        ifStatement = statement as IfStatement;
                        elseStatement = new ElseStatement();
                        SetEntityDefaultValues(elseStatement);
                        ifStatement.ElseStatement = elseStatement;
                        NonterminalToken exprToken = token.Tokens[2] as NonterminalToken;
                        ifStatement.Condition = CreateExpression(exprToken);
                        ifStatement.Condition.Parent = ifStatement;
                        firstToken = token.Tokens[0] as TerminalToken;
                        NonterminalToken stmToken = token.Tokens[4] as NonterminalToken;
                        if (stmToken != null) {
                            NonterminalToken normalStmToken = stmToken.Tokens[0] as NonterminalToken;
                            if (normalStmToken != null) {
                                NonterminalToken blockToken = normalStmToken.Tokens[0] as NonterminalToken;
                                if (blockToken != null) {
                                    lastToken = blockToken.Tokens[blockToken.Tokens.Length - 1] as TerminalToken;
                                    NonterminalToken stmListToken = blockToken.Tokens[1] as NonterminalToken;
                                    if (stmListToken != null) {
                                        ProcessStatementList(ifStatement, stmListToken);
                                    }

                                    ifStatement.StartLine = firstToken.Location.LineNr;
                                    ifStatement.StartColumn = firstToken.Location.ColumnNr;
                                    ifStatement.EndLine = lastToken.Location.LineNr;
                                    ifStatement.EndColumn = lastToken.Location.ColumnNr;
                                }
                            }
                        }

                        stmToken = token.Tokens[6] as NonterminalToken;
                        if (stmToken != null) {
                            firstToken = token.Tokens[5] as TerminalToken;
                            if (stmToken.Tokens[0] is TerminalToken) {
                                lastToken = GetLastInnermostTerminalToken(stmToken.Tokens[stmToken.Tokens.Length - 1] as NonterminalToken);
                                elseStatement.StartLine = firstToken.Location.LineNr;
                                elseStatement.StartColumn = firstToken.Location.ColumnNr;
                                elseStatement.EndLine = lastToken.Location.LineNr;
                                elseStatement.EndColumn = lastToken.Location.ColumnNr;
                                elseStatement.Children.Add(CreateStatement(stmToken, stmToken.Tokens.Length == 7 ? StatementType.IfElseStatement : StatementType.IfStatement));
                            } else {
                                NonterminalToken normalStmToken = stmToken.Tokens[0] as NonterminalToken;
                                if (normalStmToken != null) {
                                    NonterminalToken blockToken = normalStmToken.Tokens[0] as NonterminalToken;
                                    if (blockToken != null) {
                                        lastToken = blockToken.Tokens[blockToken.Tokens.Length - 1] as TerminalToken;
                                        NonterminalToken stmListToken = blockToken.Tokens[1] as NonterminalToken;
                                        if (stmListToken != null) {
                                            ProcessStatementList(elseStatement, stmListToken);
                                        }

                                        elseStatement.StartLine = firstToken.Location.LineNr;
                                        elseStatement.StartColumn = firstToken.Location.ColumnNr;
                                        elseStatement.EndLine = lastToken.Location.LineNr;
                                        elseStatement.EndColumn = lastToken.Location.ColumnNr;
                                    }
                                }
                            }
                        }

                        break;
                    case StatementType.IfStatement:
                        statement = new IfStatement();
                        ifStatement = statement as IfStatement;
                        exprToken = token.Tokens[2] as NonterminalToken;
                        ifStatement.Condition = CreateExpression(exprToken);
                        ifStatement.Condition.Parent = ifStatement;
                        stmToken = token.Tokens[4] as NonterminalToken;
                        firstToken = token.Tokens[0] as TerminalToken;
                        if (stmToken != null) {
                            NonterminalToken normalStmToken = stmToken.Tokens[0] as NonterminalToken;
                            if (normalStmToken != null) {
                                NonterminalToken blockToken = normalStmToken.Tokens[0] as NonterminalToken;
                                if (blockToken != null) {
                                    lastToken = blockToken.Tokens[blockToken.Tokens.Length - 1] as TerminalToken;
                                    NonterminalToken stmListToken = blockToken.Tokens[1] as NonterminalToken;
                                    if (stmListToken != null) {
                                        ProcessStatementList(ifStatement, stmListToken);
                                    }
                                }
                            }
                        }

                        break;
                    case StatementType.ReturnStatement:
                        statement = new ReturnStatement();
                        returnStatement = statement as ReturnStatement;
                        exprToken = token.Tokens[1] as NonterminalToken;
                        firstToken = token.Tokens[0] as TerminalToken;
                        lastToken = token.Tokens[token.Tokens.Length - 1] as TerminalToken;
                        returnStatement.ReturnValue = CreateExpression(exprToken);
                        if (returnStatement.ReturnValue != null) {
                            returnStatement.ReturnValue.Parent = returnStatement;
                        }

                        break;
                    case StatementType.WhileStatement:
                        statement = new WhileStatement();
                        whileStatement = statement as WhileStatement;
                        exprToken = token.Tokens[2] as NonterminalToken;
                        whileStatement.Condition = CreateExpression(exprToken);
                        whileStatement.Condition.Parent = whileStatement;
                        stmToken = token.Tokens[4] as NonterminalToken;
                        firstToken = token.Tokens[0] as TerminalToken;
                        if (stmToken != null) {
                            NonterminalToken normalStmToken = stmToken.Tokens[0] as NonterminalToken;
                            if (normalStmToken != null) {
                                NonterminalToken blockToken = normalStmToken.Tokens[0] as NonterminalToken;
                                if (blockToken != null) {
                                    lastToken = blockToken.Tokens[blockToken.Tokens.Length - 1] as TerminalToken;
                                    NonterminalToken stmListToken = blockToken.Tokens[1] as NonterminalToken;
                                    if (stmListToken != null) {
                                        ProcessStatementList(whileStatement, stmListToken);
                                    }
                                }
                            }
                        }

                        break;
                }

                if (statement != null) {
                    SetEntityDefaultValues(statement);
                }

                if (firstToken != null && lastToken != null && !handled) {
                    statement.StartLine = firstToken.Location.LineNr;
                    statement.StartColumn = firstToken.Location.ColumnNr;
                    statement.EndLine = lastToken.Location.LineNr;
                    statement.EndColumn = lastToken.Location.ColumnNr;
                }

                return statement;
            }

            return null;
        }

        private void ProcessStatementList(EntityWithBlock entityWithBlock, NonterminalToken token) {
            foreach (Token childToken in token.Tokens) {
                NonterminalToken nonterminalToken = childToken as NonterminalToken;
                if (nonterminalToken != null) {
                    if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STM || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STM2) {
                        NonterminalToken usefulToken = nonterminalToken.Tokens[0] as NonterminalToken;
                        if (usefulToken != null) {
                            if (usefulToken.Rule.Id == (int)RuleConstants.RULE_NORMALSTM_SEMI) {
                                usefulToken = usefulToken.Tokens[0] as NonterminalToken;
                            }

                            Entity entity = ProcessNonterminalTokensOfToken(token, usefulToken, new Token[] { usefulToken });
                            if (entity != null) {
                                entity.Parent = entityWithBlock;
                                if (entity is Variable) {
                                    if (!entitySpecificVariableOrderingTable.ContainsKey(entityWithBlock)) {
                                        entitySpecificVariableOrderingTable[entityWithBlock] = 0;
                                    }

                                    ((Variable)entity).OrderIndex = entitySpecificVariableOrderingTable[entityWithBlock];
                                    entitySpecificVariableOrderingTable[entityWithBlock]++;
                                }
                                
                                if (entity is Expression) {
                                    entityWithBlock.Children.Add(entity);
                                }
                            }
                        }
                    } else if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STM_IF_LPARAN_RPARAN || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STM_IF_LPARAN_RPARAN_ELSE || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STM_WHILE_LPARAN_RPARAN) {
                        Entity entity = ProcessNonterminalTokensOfToken(token, nonterminalToken, new Token[] { nonterminalToken });
                        if (entity != null) {
                            entity.Parent = entityWithBlock;
                            if (entity is Expression) {
                                entityWithBlock.Children.Add(entity);
                            }
                        }
                    } else if (nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STMLIST || nonterminalToken.Rule.Id == (int)RuleConstants.RULE_STMLIST2) {
                        ProcessStatementList(entityWithBlock, nonterminalToken);
                    }
                }
            }
        }

        private Entity ProcessNonterminalTokensOfToken(NonterminalToken parent, NonterminalToken token, Token[] tokens) {
            if (!processedTokens.Contains(token)) {
                Entity entity = null;
                foreach (Token childNormalToken in tokens) {
                    NonterminalToken childToken = childNormalToken as NonterminalToken;
                    if (childToken != null) {
                        switch (childToken.Rule.Id) {
                            // Functions
                            case (int)RuleConstants.RULE_FUNCPROTO_LPARAN_RPARAN_SEMI:
                            case (int)RuleConstants.RULE_FUNCPROTO_LPARAN_RPARAN_SEMI2:
                                // Function prototypes: void my_func(string param1, int param2);
                                Function function = CreateFunction(childToken, false, true);
                                entities.Add(function);
                                entity = function;
                                break;
                            case (int)RuleConstants.RULE_FUNCDECL_LPARAN_RPARAN:
                            case (int)RuleConstants.RULE_FUNCDECL_LPARAN_RPARAN2:
                                // Function declaration: void my_func(string param1, int param2) { ... }
                                function = CreateFunction(childToken, false, false);
                                entities.Add(function);
                                entity = function;
                                break;
                            case (int)RuleConstants.RULE_NATIVEDECL_NATIVE_LPARAN_RPARAN_SEMI:
                            case (int)RuleConstants.RULE_NATIVEDECL_NATIVE_LPARAN_RPARAN_SEMI2:
                                function = CreateFunction(childToken, true, true);
                                entities.Add(function);
                                entity = function;
                                break;
                            // Variables
                            case (int)RuleConstants.RULE_VARDECL_SEMI:
                            case (int)RuleConstants.RULE_VARDECL_SEMI2:
                            case (int)RuleConstants.RULE_VARDECL_SEMI3:
                            case (int)RuleConstants.RULE_VARDECL_SEMI4:
                            case (int)RuleConstants.RULE_VARDECL_SEMI5:
                            case (int)RuleConstants.RULE_VARDECL_SEMI6:
                            case (int)RuleConstants.RULE_VARDECL_SEMI7:
                            case (int)RuleConstants.RULE_VARDECL_SEMI8:
                                // Variable declaration: int var = 8;
                                Variable variable = CreateVariable(childToken);
                                if (parent.Rule.Id == (int)RuleConstants.RULE_DECL4 || parent.Rule.Id == (int)RuleConstants.RULE_DECLS || parent.Rule.Id == (int)RuleConstants.RULE_DECLS2) {
                                    if (!globalOrderingTable.ContainsKey(currentFileName)) {
                                        globalOrderingTable[currentFileName] = 0;
                                    }

                                    variable.OrderIndex = globalOrderingTable[currentFileName];
                                    globalOrderingTable[currentFileName]++;
                                    entities.Add(variable);
                                }

                                entity = variable;
                                break;
                            // Includes
                            case (int)RuleConstants.RULE_INCLUDEDECL_INCLUDE_STRINGLITERAL:
                                Include include = CreateInclude(childToken);
                                entities.Add(include);
                                entity = include;
                                break;
                            // Structs
                            case (int)RuleConstants.RULE_STRUCTDECL_STRUCT_LBRACE_RBRACE_SEMI:
                                // Struct declaration: struct my_struct { ... };
                                Struct s = CreateStruct(childToken);
                                entities.Add(s);
                                entity = s;
                                break;
                            // Typedefs
                            case (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI:
                            case (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI2:
                            case (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI3:
                            case (int)RuleConstants.RULE_TYPEDEFDECL_TYPEDEF_SEMI4:
                                Typedef typedef = CreateTypedef(childToken);
                                entities.Add(typedef);
                                entity = typedef;
                                break;
                            // Expressions
                            case (int)RuleConstants.RULE_EXPR:
                                Expression expression = CreateExpression(childToken);
                                entity = expression;
                                break;
                            // Statements
                            case (int)RuleConstants.RULE_NORMALSTM_BREAK_SEMI:
                                Statement statement = CreateStatement(childToken, StatementType.BreakStatement);
                                entity = statement;
                                break;
                            case (int)RuleConstants.RULE_NORMALSTM_CONTINUE_SEMI:
                                statement = CreateStatement(childToken, StatementType.ContinueStatement);
                                entity = statement;
                                break;
                            case (int)RuleConstants.RULE_STM_IF_LPARAN_RPARAN:
                                statement = CreateStatement(childToken, StatementType.IfStatement);
                                entity = statement;
                                break;
                            case (int)RuleConstants.RULE_STM_IF_LPARAN_RPARAN_ELSE:
                            case (int)RuleConstants.RULE_THENSTM_IF_LPARAN_RPARAN_ELSE:
                                statement = CreateStatement(childToken, StatementType.IfElseStatement);
                                entity = statement;
                                break;
                            case (int)RuleConstants.RULE_NORMALSTM_RETURN_SEMI:
                            case (int)RuleConstants.RULE_NORMALSTM_RETURN_SEMI2:
                                statement = CreateStatement(childToken, StatementType.ReturnStatement);
                                entity = statement;
                                break;
                            case (int)RuleConstants.RULE_STM_WHILE_LPARAN_RPARAN:
                            case (int)RuleConstants.RULE_THENSTM_WHILE_LPARAN_RPARAN:
                                statement = CreateStatement(childToken, StatementType.WhileStatement);
                                entity = statement;
                                break;
                        }
                    }
                }

                return entity;
            }

            return null;
        }

        private void ProcessNonterminalTokensOfTokenRecursive(NonterminalToken parent, Token token, Token[] tokens) {
            if (token != null && token is NonterminalToken) {
                ProcessNonterminalTokensOfToken(parent, token as NonterminalToken, tokens);
                foreach (Token childToken in tokens) {
                    if (childToken is NonterminalToken) {
                        ProcessNonterminalTokensOfTokenRecursive(token as NonterminalToken, childToken, (childToken as NonterminalToken).Tokens);
                    }
                }
            }
        }

        private void AcceptEvent(LALRParser parser, AcceptEventArgs args) {
            ProcessNonterminalTokensOfTokenRecursive(null, args.Token, args.Token.Tokens);
        }

        private void TokenErrorEvent(LALRParser parser, TokenErrorEventArgs args) {
            if (reportErrors) {
                string message = "Token error with input: '" + args.Token.ToString() + "'";
                ErrorSink.AddError(ErrorSink.Error.Create(message, args.Token.Location.LineNr, args.Token.Location.ColumnNr, args.Token.Location.LineNr, args.Token.Location.ColumnNr, currentFileName));
            }

            valid = false;
        }

        private void ParseErrorEvent(LALRParser parser, ParseErrorEventArgs args) {
            if (reportErrors) {
                string message = "Unexpected token '" + args.UnexpectedToken.ToString() + "'";
                ErrorSink.AddError(ErrorSink.Error.Create(message, args.UnexpectedToken.Location.LineNr, args.UnexpectedToken.Location.ColumnNr, args.UnexpectedToken.Location.LineNr, args.UnexpectedToken.Location.ColumnNr, currentFileName));
            }

            valid = false;
        }
    }
}
